﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Automate The Test  Automation Review.cs" company="">
//   
// </copyright>
// <summary>
//   The main screen.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using ATTAR;
using Outlook = Microsoft.Office.Interop.Outlook;

using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;

using System.DirectoryServices.AccountManagement;
using System.Security.Principal;
using Microsoft.Office.Interop.Outlook;
using System.Threading;

namespace ATTAR
{


    /// <summary>
    /// The main screen.
    /// </summary>
    public partial class MainScreen : Form
    {
        #region Variables

        Status overallStatus = Status.PASS;

        private ValidationConfiguration validationConfiguration;

        private List<AstNode> TimeoutAttributes;

        private List<AstNode> CompanyDatabaseCommands;

        private List<AstNode> SiteDatabaseCommands;

        private List<AstNode> SuperSiteDatabaseCommands;

        private Dictionary<string, List<string>> modifiedTables;

        private Dictionary<string, List<string>> backedUpTables;

        private List<string> restoredDatabases;

        private string databaseContextName = string.Empty;

        private int[] companyCounts = new[] { 0, 0, 0 };

        private int[] siteCounts = new[] { 0, 0, 0 };

        private int[] supersitecounts = new[] { 0, 0, 0 };

        private const string PASSED = "PASSED\r\n";

        private const string FAILED = "FAILED\r\n";

        private string validateOverallTimeOutResults = " ";

        private string validateZeroTimeOutResults = " ";

        private List<int> checkedIndices;

        private string reportHeader =
            @"
*************************************************************************************************************************************
                      Report Generated by A.T.T.A.R. on {0}  
                  
    Automation Reviewer: {1}
    Scrip path: {2}
    Script Author: {3}, {4}
    JIRA: {5}

**************************************************************************************************************************************
";

        private string finalReport = @"";

        /// <summary>
        /// The reviewer name.
        /// </summary>
        private string reviwerName = string.Empty;
        private string currentUser = string.Empty; // is it really needed?

        private string authorName = string.Empty;
        private string emailAddress = string.Empty;
        private string jiraNumber = string.Empty;

        private string currentFile = string.Empty;

        private string workingDllPath = "Click here to select a DLL";

        List<ECHOValidation> validations = new List<ECHOValidation>()
        { 
            new ECHOValidation() { Code="ModifiedDatabaseIsBackedUpAndRestored", Text="Database must be backed up and rolled back at teardown, if modified during the test", Enabled=true },
            new ECHOValidation() { Code="OverallTimeout", Text="Test overall time must be greater than the sum of testcases timeouts", Enabled=true },
            new ECHOValidation() { Code="NoTimeOutOfZero", Text="No [Timeout] value  of 0", Enabled=true},
            new ECHOValidation() { Code="RequiredCategoryAndAuthorAttributes", Text = "Each test class must have a [Category] and [Author] attributes", Enabled=true},
            new ECHOValidation() { Code="NoConditionalStatements", Text="No conditional statements", Enabled=true},
            new ECHOValidation() { Code="TryStatements",  Text="No Try-Catch or Try-Finally", Enabled=true},
            new ECHOValidation() { Code="NoUseOfDatabaseConnectionsOutsideThoseProvidedByEcho", Text="No use of database connections outside those provided by Echo", Enabled=true},
            new ECHOValidation() { Code="NoThreadSleeps", Text="No use of Thread.sleep()", Enabled=true },
            new ECHOValidation() { Code="NoSystemConsoleOrSystemLogUsage", Text="Does not call System.Console or Console.Log", Enabled=true},
            new ECHOValidation() { Code="TestsFollowBDD", Text="Use of BDD test cases format (Given, When, Then, And)", Enabled=true },
            new ECHOValidation() { Code="DescriptiveLambdaExpressions", Text="No use of 1 or 2 letters lambda expressions (ej. x =>x.  or xy => xy.) ", Enabled=true },
            new ECHOValidation() { Code="UseCacheRefreshInseteadOfIISResetWhenPosible", Text="Use cache refresh insetead of IIS reset when posible", Enabled=true },
            new ECHOValidation() { Code="UseOfStandardCorporateHeaderComents", Text="Use of standar corporate header coments", Enabled=true},
            new ECHOValidation() { Code="AllMethodsShouldHaveMetadataXmlDocumentation", Text="All methods should have metadata (xml documentation)", Enabled=true },
            new ECHOValidation() { Code="AllCriticalFunctionsInTheFixtureTeardownMustBePlacedBeforeDoingAnyGUIinteraction", Text="All critical functions in the fixture teardown must be placed before doing any GUI interaction", Enabled=true},
            new ECHOValidation() { Code="Usings", Text="Usings are to be on top and sorted", Enabled=true},
            new ECHOValidation() { Code="VariablesAndConstantDeclarationsShouldBeAtTheTop", Text="Variables and Constant declarations should be at the top", Enabled=true },
            new ECHOValidation() { Code="FixtureSetupAndFixtureTeardownLocation", Text="Fixture setup and fixture teardown should be at the top right after variables and constants declaration", Enabled=true },
            new ECHOValidation() { Code="HelpersMethodsShouldBeAtTheBottomAfterTestCases", Text="Helpers (private methods) should be at the bottom after Test cases (public methods)", Enabled=true },
            new ECHOValidation() { Code="UseOfStringFormat", Text="Use of string.Format instead of concatenating string using \"x\" + \"y\"", Enabled=true },
            new ECHOValidation() { Code="MatchingNamespaceAndFolderStructure", Text="Accurate 'Namespace' that follows folder hierarchy", Enabled=true },
        };

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="MainScreen"/> class.
        /// </summary>
        /// <summary>
        /// Initializes a new instance of the <see cref="MainScreen"/> class.
        /// </summary>
        public MainScreen(string reviewerName)
        {
            InitializeComponent();

            this.TimeoutAttributes = new List<AstNode>();
            this.CompanyDatabaseCommands = new List<AstNode>();
            this.SiteDatabaseCommands = new List<AstNode>();
            this.SuperSiteDatabaseCommands = new List<AstNode>();
            this.modifiedTables = new Dictionary<string, List<string>>();
            this.backedUpTables = new Dictionary<string, List<string>>();
            this.restoredDatabases = new List<string>();

            this.checkedIndices = new List<int>();

            this.chkSelectAll.CheckState = CheckState.Checked;

            this.reviwerName = reviewerName;
        }

        #region Form Event Handlers

        private void MainScreen_Load(object sender, EventArgs e)
        {
            this.folderBrowserDialog.SelectedPath = @"C:\projects\UltiPro.NET\AutomatedTests\Echo";
            this.autoCheckedListBox.Items.Clear();

            if (File.Exists("ValidationConfiguration.xml"))
            {
                LoadConfiguration();                               
            }
            else // Set all Validations on by default
            {
                this.validationConfiguration = new ValidationConfiguration();
                this.validationConfiguration.Validations = this.validations;

                Object[] ItemObject = new Object[validationConfiguration.Validations.Count];
                for (int i = 0; i < ItemObject.Length; i++)
                {
                    ItemObject[i] = validationConfiguration.Validations[i].Text;
                }

                this.autoCheckedListBox.Items.AddRange(ItemObject);

                for (int i = 0; i < this.autoCheckedListBox.Items.Count; i++)
                {
                    this.autoCheckedListBox.SetItemChecked(i, true);
                }
            }
        }

        private void MainScreen_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Display a MsgBox asking the user to save changes or abort. 
            if (MessageBox.Show("Are you sure you want to exit the program?", "ATTAR", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                == DialogResult.No)
            {
                e.Cancel = true;
            }
            else
            {
                e.Cancel = false;
            }
        }

        #endregion

        #region Control Event Handlers

        private void runBtn_Click(object sender, EventArgs e)
        {
            if (this.autoCheckedListBox.CheckedIndices.Count == 0)
            {
                MessageBox.Show("Please select at least 1 validation...", "No validation selected", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else if (string.IsNullOrEmpty(this.testPathTextBox.Text))
            {
                MessageBox.Show("Please select a file/folder to verify...", "No file/folder selected", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                ClearFields();

                // Disable fields before processing
                this.runBtn.Enabled = this.printBtn.Enabled = this.emailBtn.Enabled = this.saveResultsBtn.Enabled = false;

                // Populate Files List to validate
                List<string> filesList = PopulateList();

                // Process List
                ProcessList(filesList);

                // Reenable fields after processing
                this.runBtn.Enabled = this.printBtn.Enabled = this.emailBtn.Enabled = this.saveResultsBtn.Enabled = true;
            }
        }

        private void VerifyTeardownBtn_Click(object sender, EventArgs e)
        {
            RunScript(this.workingDllPath, Path.GetFileNameWithoutExtension(this.testPathTextBox.Text));
        }

        public void browseDirBtn_Click(object sender, EventArgs e)
        {
            if (this.chkProcessFolder.Checked)
            {
                if (this.folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    this.testPathTextBox.Text = folderBrowserDialog.SelectedPath;
                }
            }
            else
            {
                if (this.openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    this.testPathTextBox.Text = openFileDialog.FileName;
                }
            }
        }

        private void chkProcessFolder_CheckedChanged(object sender, EventArgs e)
        {
            this.testPathTextBox.Text = "";

            // TODO reenable when verify teardown is complete
            //this.VerifyTeardownBtn.Enabled = !this.chkProcessFolder.Checked;
        }

        private void DLLlbl_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (this.dllOpenFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.DLLlbl.Text = this.workingDllPath = this.dllOpenFileDialog.FileName;

                // save dll path in xml
                if (!File.Exists("@ValidationConfiguration.xml"))
                    SerializeConfiguration();

                //ValidationConfigurationSerialization.SaveWorkingDll(this.workingDllPath);
            }
        }

        private void browseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.dllOpenFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.DLLlbl.Text = this.workingDllPath = this.dllOpenFileDialog.FileName;

                // save dll path in xml
                if (!File.Exists("@ValidationConfiguration.xml"))
                    SerializeConfiguration();
            }
        }

        private void autoCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
         {
            this.validationConfiguration.Validations[e.Index].Enabled = (e.NewValue == CheckState.Checked) ? true : false;

            var validations = from valid in validationConfiguration.Validations
                              where valid.Enabled
                              select valid;

            this.chkSelectAll.Checked = (validations.ToList().Count == this.autoCheckedListBox.Items.Count) ? true : false;                 
        }

        private void chkSelectAll_MouseClick(object sender, MouseEventArgs e)
        {
            foreach (ECHOValidation validation in this.validationConfiguration.Validations)
                if (this.chkSelectAll.Checked)
                    validation.Enabled = true;
                else
                    validation.Enabled = false;

            for (int i = 0; i < validationConfiguration.Validations.Count; i++)
            {
                this.autoCheckedListBox.SetItemChecked(i, validationConfiguration.Validations[i].Enabled);
            } 
        }

        private void chkSelectAllManual_CheckedChanged(object sender, EventArgs e)
        {
            for (int i = 0; i < this.checkedListBox.Items.Count; i++)
            {
                if (this.chkSelectAllManual.Checked)
                    this.checkedListBox.SetItemChecked(i, true);
                else
                    this.checkedListBox.SetItemChecked(i, false);
            }
        }

        private void saveConfigurationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SerializeConfiguration();
        }

        private void loadConfigurationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.autoCheckedListBox.Items.Clear();
            LoadConfiguration();
        }

        private void emailBtn_Click(object sender, EventArgs e)
        {
            string fileLocation = string.Format(@"{0}\AutomationReviewReport.rtf", System.Windows.Forms.Application.StartupPath);
            this.reportColoredBox.SaveFile(fileLocation);

            Outlook.Application outlookApp = new Outlook.Application();
            MailItem message = (MailItem)outlookApp.CreateItem(OlItemType.olMailItem);
            message.To = emailAddress;
            message.Subject = "Automation Review Report for: " + this.jiraNumber;
            message.HTMLBody = "Please see the attached review report.";
            message.Attachments.Add(fileLocation, Outlook.OlAttachmentType.olByValue, 1, "AutomationReviewReport.rtf");
            message.Display(true);
        }

        private void printBtn_Click(object sender, EventArgs e)
        {
            if (this.printDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
            }
        }

        private void saveResultsBtn_Click(object sender, EventArgs e)
        {
            string saveLocation = "";

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                saveLocation = this.saveFileDialog.FileName;

                this.reportColoredBox.SaveFile(saveLocation);

                if (File.Exists(saveLocation))
                    MessageBox.Show("Your report was successfully saved", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        #endregion

        #region HelperMethods

        private List<string> PopulateList()
        {
            List<string> filesList = new List<string>();

            // folder
            if (this.chkProcessFolder.Checked)
            {
                string[] files = Directory.GetFiles(this.testPathTextBox.Text, "*.cs", SearchOption.AllDirectories);

                filesList = files.ToList();
            }
            else // single file
            {
                if (File.Exists(this.testPathTextBox.Text))
                {
                    filesList.Add(this.testPathTextBox.Text);
                }
                else
                    MessageBox.Show("The file was not found...", "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return filesList;
        }

        private void ProcessList(List<string> filesList)
        {
            List<Status> statuses = new List<Status>();
            this.overallStatus = Status.PASS;

            foreach (string file in filesList)
            {
                ProcessFile(file, ref statuses);
            }

            // Done validating
            this.reportColoredBox.ReadOnly = false;
            this.reportColoredBox.SelectionStart = 0;

            foreach (Status status in statuses)
            {
                if (status == Status.FAIL)
                {
                    overallStatus = Status.FAIL;
                    break;
                }
            }

            // If all validations passed for all files, add tropy to report
            if (this.overallStatus == Status.PASS && !string.IsNullOrEmpty(this.reportColoredBox.Text))
            {
                if (File.Exists(String.Format(@"{0}\Images\trophygold.png", System.Windows.Forms.Application.StartupPath)))
                {
                    Clipboard.SetImage(Image.FromFile(String.Format(@"{0}\Images\trophygold.png", System.Windows.Forms.Application.StartupPath)));
                }
                else
                    Clipboard.Clear();

                reportColoredBox.Paste();
            }

            this.reportColoredBox.ReadOnly = true;
            this.automatedTab.SelectedTab = reportTab;
        }

        private void ProcessFile(string filePath, ref List<Status> statuses)
        {
            if (File.Exists(filePath) && !Path.GetDirectoryName(filePath).Substring(Path.GetDirectoryName(filePath).LastIndexOf("\\") + 1).Equals("Properties"))
            {
                ECHOFileParser parser = new ECHOFileParser();
                SyntaxTree syntaxTree = parser.Parse(filePath);

                ECHOElements elements = new ECHOElements(Path.GetFileNameWithoutExtension(filePath), syntaxTree);

                // Is a test
                if (elements.IsTestFixture())
                {
                    string today = DateTime.Today.ToString("MM-dd-yyyy");

                    this.authorName = elements.GetAuthor();
                    this.emailAddress = elements.GetEmailAddress();
                    this.jiraNumber = elements.GetJIRANumber();

                    this.reportHeader = string.Format(reportHeader, today, this.reviwerName, filePath, authorName,
                        emailAddress, jiraNumber);

                    this.reportColoredBox.AppendText(reportHeader, Color.Blue);
                    this.reportColoredBox.AppendText(" ");

                    if (elements.MethodDeclarations.Count > 0)
                    {
                        CheckedListBox.CheckedIndexCollection selectedIndices = this.autoCheckedListBox.CheckedIndices;
                        
                        ECHOValidator validator = new ECHOValidator(filePath, this.validationConfiguration, elements, ref this.reportColoredBox);
                        this.reportColoredBox.ReadOnly = false;
                        Status status = validator.Validate();
                        this.reportColoredBox.ReadOnly = true;

                        statuses.Add(status);
                    }
                    this.jiraTextBox.Text = this.jiraNumber;
                }
            }
        }
                        
        private void RunScript(string assembly, string scriptName)
        {
            string results = string.Format("{0}-Results.html", scriptName);

            System.Diagnostics.Process process = new System.Diagnostics.Process();
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
            startInfo.FileName = @"C:\Program Files\Gallio\bin\Gallio.Echo.exe";
            startInfo.Arguments = string.Format(@"/rt:html /rd:\{2} /rnf:{1} {0} /f:Type:{1}", assembly, scriptName, results);
            startInfo.UseShellExecute = false;
            process.StartInfo = startInfo;
            process.Start();
        }

        private void ClearFields()
        {
            this.reportHeader =
            @"
*************************************************************************************************************************************
                      Report Generated by A.T.T.A.R. on {0}  
                  
    Automation Reviewer: {1}
    Scrip path: {2}
    Script Author: {3}, {4}
    JIRA: {5}

**************************************************************************************************************************************
";
            this.reportColoredBox.Clear();

            this.validateOverallTimeOutResults = " ";
            this.validateZeroTimeOutResults = " ";

            this.TimeoutAttributes.Clear();

            this.CompanyDatabaseCommands.Clear();
            this.SiteDatabaseCommands.Clear();
            this.SuperSiteDatabaseCommands.Clear();

            this.modifiedTables.Clear();
            this.backedUpTables.Clear();
            this.restoredDatabases.Clear();

            string databaseContextName = string.Empty;

            companyCounts[0] = companyCounts[1] = companyCounts[2] = 0;
            siteCounts[0] = siteCounts[1] = siteCounts[2] = 0;
            supersitecounts[0] = supersitecounts[1] = supersitecounts[2] = 0;
        }

        private void LoadConfiguration()
        {
            this.validationConfiguration = this.DeserialzeConfiguration();

            Object[] ItemObject = new Object[validationConfiguration.Validations.Count];
            for (int i = 0; i < ItemObject.Length; i++)
            {
                ItemObject[i] = validationConfiguration.Validations[i].Text;
            }

            this.autoCheckedListBox.Items.AddRange(ItemObject);
            
            for (int i = 0; i < validationConfiguration.Validations.Count; i++)
            {
                this.autoCheckedListBox.SetItemChecked(i, validationConfiguration.Validations[i].Enabled);
            }

            //this.workingDllPath = validationConfiguration.workingDllPath;                        
        }

        private void SerializeConfiguration()
        {
            //this.validationConfiguration.workingDllPath = this.workingDllPath;

            ValidationConfigurationSerialization.ValidationConfiguration_Serialize(this.validationConfiguration);
        }

        private ValidationConfiguration DeserialzeConfiguration()
        {
            return ValidationConfigurationSerialization.ValidationConfiguration_Deserialize("ValidationConfiguration.xml");
        }
        
        #endregion
    }
}

//override to add color to text
/// <summary>
/// The rich text box extensions.
/// </summary>
public static class RichTextBoxExtensions
{
    /// <summary>
    /// The append text.
    /// </summary>
    /// <param name="box">
    /// The box.
    /// </param>
    /// <param name="text">
    /// The text.
    /// </param>
    /// <param name="color">
    /// The color.
    /// </param>
    public static void AppendText(this RichTextBox box, string text, Color color)
    {
        box.SelectionStart = box.TextLength;
        box.SelectionLength = 0;

        box.SelectionColor = color;
        box.AppendText(text);
        box.SelectionColor = box.ForeColor;
    }
}